#ifndef __INCLUDE_UTILS_H

#define __INCLUDE_UTILS_H

#include "common.h"
#include "vm.h"

void* mem_manager(VM *vm, void *ptr, uint32_t old_size, uint32_t new_size);

#define ALLOCATE(vm_ptr, type) \
    (type*)mem_manager(vm_ptr, NULL, 0, sizeof(type))

#define ALLOCATE_EXTRA(vm_ptr, main_type, extra_size) \
    (main_type*)mem_manager(vm_ptr, NULL, 0, sizeof(main_type) + extra_size)

#define ALLOCATE_ARRAY(vm_ptr, type, count) \
    (type*)mem_manager(vm_ptr, NULL, 0, sizeof(type) * count)

#define DEALLOCATE_ARRAY(vm_ptr, array_ptr, count) \
    mem_manager(vm_ptr, array_ptr, sizeof(array_ptr[0]) * count, 0)

#define DEALLOCATE(vm_ptr, mem_ptr) mem_manager(vm_ptr, mem_ptr, 0, 0)

typedef struct 
{
    char *str;
    uint32_t length;
} String;

typedef struct 
{
    uint32_t length; // 除了\0之外的字符个数
    char start[0]; // 柔性数组
} CharValue; // 字符串缓冲区

#define DECLARE_BUFFER_TYPE(type) \
    typedef struct \
    { \
        type *datas; \
        uint32_t count; \
        uint32_t capacity; \
    } type##Buffer; \
    void type##_buffer_init(type##Buffer *buf); \
    void type##_buffer_fill_write(VM *vm, type##Buffer *buf, type data, uint32_t fill_count); \
    void type##_buffer_add(VM *vm, type##Buffer *buf, type data); \
    void type##_buffer_clear(VM *vm, type##Buffer *buf);

/**
 * @brief 
 * type##_buffer_init
 * type##_buffer_fill_write 写入fill_count个类型为type的数据data
 * type##_buffer_add
 * type##_buffer_clear
*/
#define DEFINE_BUFFER_METHOD(type) \
    void type##_buffer_init(type##Buffer *buf) \
    { \
        buf->datas = NULL; \
        buf->count = buf->capacity = 0; \
    } \
    void type##_buffer_fill_write(VM *vm, type##Buffer *buf, type data, uint32_t fill_count) \
    { \
        uint32_t new_counts = buf->capacity + fill_count; \
        if (new_counts > buf->capacity) \
        { \
            size_t old_size = buf->capacity * sizeof(type); \
            buf->capacity = ceil_to_power_of_2(new_counts); \
            size_t new_size = buf->capacity * sizeof(type); \
            ASSERT(new_size > old_size, "faint...memory allocate!"); \
            buf->datas = (type *)mem_manager(vm, buf->datas, old_size, new_size); \
        } \
        uint32_t cnt = 0; \
        while (cnt < fill_count) \
        { \
            buf->datas[buf->count ++] = data; \
            cnt ++; \
        } \
    } \
    void type##_buffer_add(VM *vm, type##Buffer *buf, type data) \
    { \
        type##_buffer_fill_write(vm, buf, data, 1); \
    } \
    void type##_buffer_clear(VM *vm, type##Buffer *buf) \
    { \
        size_t old_size = buf->capacity * sizeof(buf->datas[0]); \
        mem_manager(vm, buf->datas, old_size, 0); \
        type##_buffer_init(buf); \
    }

#define SymbolTable StringBuffer

typedef uint8_t Byte;
typedef char Char;
typedef int Int;

DECLARE_BUFFER_TYPE(String)
DECLARE_BUFFER_TYPE(Int)
DECLARE_BUFFER_TYPE(Char)
DECLARE_BUFFER_TYPE(Byte)

typedef enum 
{
    ERROR_IO,
    ERROR_MEM,
    ERROR_LEX,
    ERROR_COMPILE,
    ERROR_RUNTIME
} ErrorType;

void error_report(void *parser, ErrorType error_type, const char *fmt, ...);

#define IO_ERROR(...) \
    error_report(NULL, ERROR_IO, __VA_ARGS__)
#define MEM_ERROR(...) \
    error_report(NULL, ERROR_MEM, __VA_ARGS__)
#define LEX_ERROR(parser, ...) \
    error_report(NULL, ERROR_LEX, __VA_ARGS__)
#define COMPILE_ERROR(parser, ...) \
    error_report(NULL, ERROR_COMPILE, __VA_ARGS__)
#define RUNTIME_ERROR(...) \
    error_report(NULL, ERROR_RUNTIME, __VA_ARGS__)

uint32_t ceil_to_power_of_2(uint32_t v);
void symbol_table_clear(VM *vm, SymbolTable *buffer);

#define DEFAULT_BUFFER_SIZE 512

#endif